package util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.jsoup.nodes.Document;

import entities.Domain;

public class CatchLanguage {

	private static List<String> linuxDistributions = null;
	private static List<String> listWebServer = null;

	static {
		if (linuxDistributions == null || linuxDistributions.size() == 0) {
			linuxDistributions = new ArrayList<String>();
			linuxDistributions.add("64 Studio");
			linuxDistributions.add("aptosid");
			linuxDistributions.add("Bharat Operating System Solutions");
			linuxDistributions.add("Canaima");
			linuxDistributions.add("Caixa Mágica");
			linuxDistributions.add("Corel Linux");
			linuxDistributions.add("CrunchBang");
			linuxDistributions.add("Dreamlinux");
			linuxDistributions.add("Elive");
			linuxDistributions.add("Emdebian Grip");
			linuxDistributions.add("Finnix");
			linuxDistributions.add("gNewSense");
			linuxDistributions.add("grml");
			linuxDistributions.add("HandyLinux");
			linuxDistributions.add("Instant WebKiosk");
			linuxDistributions.add("Kali Linux");
			linuxDistributions.add("Kanotix");
			linuxDistributions.add("Knoppix");
			linuxDistributions.add("Kurumin");
			linuxDistributions.add("LEAF Project");
			linuxDistributions.add("LiMux");
			linuxDistributions.add("LinuxBBQ");
			linuxDistributions.add("Linux Mint Debian Edition");
			linuxDistributions.add("Maemo");
			linuxDistributions.add("MEPIS");
			linuxDistributions.add("MintPPC");
			linuxDistributions.add("Musix GNU+Linux");
			linuxDistributions.add("NepaLinux");
			linuxDistributions.add("OpenZaurus");
			linuxDistributions.add("Pardus");
			linuxDistributions.add("Parsix");
			linuxDistributions.add("PureOS");
			linuxDistributions.add("Rxart");
			linuxDistributions.add("Sacix");
			linuxDistributions.add("Siduction");
			linuxDistributions.add("Skolelinux");
			linuxDistributions.add("SolusOS");
			linuxDistributions.add("SolydXK");
			linuxDistributions.add("SteamOS");
			linuxDistributions.add("Sunwah Linux");
			linuxDistributions.add("Symphony OS");
			linuxDistributions.add("SalineOS");
			linuxDistributions.add("TAILS");
			linuxDistributions.add("Ubuntu");
			linuxDistributions.add("Ulteo");
			linuxDistributions.add("Univention Corporate");
			linuxDistributions.add("Webconverger");
			linuxDistributions.add("Vyatta");
		}
		if (listWebServer == null || listWebServer.size() == 0) {
			listWebServer = new ArrayList<String>();
			listWebServer.add("Microsoft-IIS");
			listWebServer.add("Apache-Coyote");
			listWebServer.add("Apache Tomcat");
			listWebServer.add("gunicorn");
			listWebServer.add("DecosetterServer");
			listWebServer.add("Zope");
			listWebServer.add("Resin");
			listWebServer.add("Phusion_Passenger");
			listWebServer.add("Mongrel");
			listWebServer.add("WEBrick");
			listWebServer.add("Thin");
			listWebServer.add("Tcl-Webserver");
			listWebServer.add("Nginx");
			listWebServer.add("lighttpd");
			listWebServer.add("Jigsaw");
			listWebServer.add("Klone");
			listWebServer.add("Abyss");
			listWebServer.add("Oracle");
			listWebServer.add("X5");
			listWebServer.add("Xitami");
			listWebServer.add("Zeus");
		}
	}

	public static Map<String, String> loadMapHeader(Domain d) {
		Map<String, String> mapHeader = new HashMap<String, String>();
		String[] linesHeader = d.getHeader().split("\r\n|\r|\n");
		for (int i = 0; i < linesHeader.length; i++) {
			String[] splitLine = linesHeader[i].split(":");
			String value = "";
			if (splitLine.length >= 2) {
				for (int j = 1; j < splitLine.length; j++) {
					value += splitLine[j];
				}

				if (mapHeader.containsKey(splitLine[0])) {
					String recentValue = mapHeader.get(splitLine[0]);
					mapHeader.put(splitLine[0], recentValue + ", " + value);
				} else {
					mapHeader.put(splitLine[0], value);
				}
			}
		}
		return mapHeader;
	}

	@SuppressWarnings("unchecked")
	public static void catchLanguage(Map<String, String> detectHeaderMap,
			String[] cookieNames, String[] footerWords,
			Map<String, Object> obj, String languageName) {
		Domain d = (Domain) obj.get("domain");
		if (d != null
				&& d.getServerLanguage() != null
				&& (d.getServerLanguage().equals("php") || d
						.getServerLanguage().equals("CFML"))) {
			boolean gotcha = false;
			String serverValue = "";

			/*
			 * There're three ways to check program language, based on :
			 * response header (priority 1), cookie (priority 2) and footer
			 * (priority 3). We'll define array of footer word, server name,
			 * cookie name.
			 */

			// Load Header
			Map<String, String> mapHeader;
			if (obj.containsKey("mapHeader_240187")) {
				mapHeader = (Map<String, String>) obj.get("mapHeader_240187");
			} else {
				mapHeader = CatchLanguage.loadMapHeader(d);
				obj.put("mapHeader_240187", mapHeader);
			}

			if (mapHeader != null && mapHeader.size() > 0) {
				// Catch by Response Header
				if (detectHeaderMap != null && detectHeaderMap.size() > 0) {
					for (Entry<String, String> entry : detectHeaderMap
							.entrySet()) {
						String detectKey = entry.getKey();
						String detectValue = entry.getValue();
						if (mapHeader.containsKey(detectKey)) {
							String headerValue = mapHeader.get(detectKey);
							if (detectValue.length() == 0) {
								gotcha = true;
								break;
							} else {
								String[] detectSplit = detectValue.split(",");
								for (String tempString : detectSplit) {
									if (headerValue.toLowerCase().contains(
											tempString.trim().toLowerCase())) {
										gotcha = true;
										break;
									}
								}
								if (gotcha) {
									break;
								}
							}
						}
					}
				}

				// Catch by Cookie
				if (!gotcha) {
					String cookie = mapHeader.get("Set-Cookie");
					if (cookieNames != null && cookieNames.length > 0
							&& cookie != null && cookie.length() > 0) {
						gotcha = CatchLanguage.stringContainListItem(cookie,
								cookieNames);
					}
				}

				// Catch by footer
				if (!gotcha) {
					String footer = "";
					if (obj.containsKey("footer_240187")) {
						footer = (String) obj.get("footer_240187");
					} else {
						Document doc = (Document) obj.get("doc");
						footer = doc.select("footer").text();
						if (footer == null || footer.length() < 1) {
							footer = doc.select("#footer").text();
							if (footer == null || footer.length() < 1) {
								footer = doc.select(".footer").text();
							}
						}
						if (footer != null && footer.length() > 0) {
							obj.put("footer_240187", footer);
						}
					}
					if (footerWords != null && footerWords.length > 0
							&& footer != null && footer.length() > 0) {
						gotcha = CatchLanguage.stringContainListItem(footer,
								footerWords);
					}
				}
				serverValue = mapHeader.get("Server");
			}

			if (gotcha) {
				d.setServerLanguage(languageName);
			}
			// Catch Server OS & WebServer
			if (d.getServerOs().equalsIgnoreCase("Linux")) {
				catchServerOs(serverValue, d.getServerLanguage(), d);
			}
			if (d.getWebServer().equalsIgnoreCase("Apache")) {
				catchWebserver(serverValue, d.getServerLanguage(), d);
			}
		}
	}

	// Checking Server OS
	public static void catchServerOs(String serverValue, String serverLanguage,
			Domain d) {
		if (serverValue != null) {
			if (serverLanguage.toLowerCase().contains("asp")) {
				d.setServerOs("Microsoft Windows");
			} else {
				for (String e : linuxDistributions) {
					if (serverValue.toLowerCase().contains(e.toLowerCase())) {
						d.setServerOs(e);
						break;
					}
				}
			}
		}
	}

	// Checking WebServer
	public static void catchWebserver(String serverValue,
			String serverLanguage, Domain d) {
		if (serverValue != null) {
			if (serverLanguage.toLowerCase().contains("asp")
					|| d.getServerOs().contains("Windows")) {
				d.setWebServer("Microsoft-IIS");
			} else {
				boolean gotcha = false;
				for (String e : listWebServer) {
					if (serverValue.toLowerCase().contains(e.toLowerCase())) {
						d.setWebServer(e);
						gotcha = true;
						break;
					}
				}
				if (!gotcha) {
					d.setWebServer(serverValue);
				}
			}
		}
	}

	public static boolean stringContainListItem(String str, String[] list) {
		boolean catched = false;
		for (String n : list) {
			if (str.toLowerCase().contains(n.toLowerCase())) {
				catched = true;
				break;
			}
		}
		return catched;
	}
}
